package es.esi.gemde.modeltransformator.acceleoengine;

import java.io.File;
import java.net.URI;
import java.util.Vector;

import org.eclipse.acceleo.common.internal.utils.AcceleoPackageRegistry;
import org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator;
import org.eclipse.acceleo.model.mtl.Module;
import org.eclipse.acceleo.model.mtl.Template;
import org.eclipse.acceleo.model.mtl.resource.AcceleoResourceFactoryRegistry;
import org.eclipse.acceleo.model.mtl.resource.AcceleoResourceSetImpl;
import org.eclipse.acceleo.parser.AcceleoParserProblem;
import org.eclipse.acceleo.parser.AcceleoSourceBuffer;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.plugin.EcorePlugin;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;

import es.esi.gemde.core.utils.GEMDEUtils;
import es.esi.gemde.modeltransformator.service.ITransformation;

@SuppressWarnings("restriction")
public class GEMDEAcceleoGenerator extends AbstractAcceleoGenerator {

	private EObject[] inputs;
	private ITransformation transformation;
	private boolean isInitialized = false;
	
	private ResourceSet rs = null;
	
	private Vector<String> templateNames = new Vector<String>();
	
	private String errors;
	
	
	public GEMDEAcceleoGenerator(EObject[] inputs,	ITransformation transformation, String outputPath) {
		this.inputs = inputs;
		this.transformation = transformation;
		this.targetFolder = new File(outputPath);
	}
	
	@Override
	public String getModuleName() {
		return module.getName();
	}

	@Override
	public String[] getTemplateNames() {
		return templateNames.toArray(new String[0]);
	}
	
	@SuppressWarnings({ "deprecation" })
	public void initialize() {
		isInitialized = false;
		rs = new AcceleoResourceSetImpl();
		rs.setPackageRegistry(AcceleoPackageRegistry.INSTANCE);

		resourceFactoryRegistry = rs.getResourceFactoryRegistry();
		rs.setResourceFactoryRegistry(new AcceleoResourceFactoryRegistry(resourceFactoryRegistry));

		originalResources.addAll(rs.getResources());

		URIConverter uriConverter = createURIConverter();
		if (uriConverter != null) {
			rs.setURIConverter(uriConverter);
		}

		// make sure that metamodel projects in the workspace override those in plugins
		rs.getURIConverter().getURIMap().putAll(EcorePlugin.computePlatformURIMap());

		registerResourceFactories(rs);
		registerPackages(rs);

		addListeners();
		addProperties();
		
		
		Vector<AcceleoSourceBuffer> buffers = new Vector<AcceleoSourceBuffer>();

		// Create the ASTs of each of the input files
		for (URI uri : transformation.getTransformationURIs()) {
			File input = GEMDEUtils.uri2file(uri);
			AcceleoSourceBuffer sb = new AcceleoSourceBuffer(input);
			Resource res = rs.createResource(org.eclipse.emf.common.util.URI.createURI(uri.toString()));

			sb.createCST();
			sb.createAST(res);

			buffers.add(sb);
		}

		// Resolve the dependencies of the ASTs
		for (AcceleoSourceBuffer sb : buffers) {
			sb.resolveAST();
		}

		// Check for errors
		errors = "";
		for (AcceleoSourceBuffer sb : buffers) {
			for (AcceleoParserProblem p : sb.getProblems().getList()) {
				errors += p.getMessage() + "\n";
			}
		}
		
		if (!errors.equals("")) {
			return;  
		}
		
		// Find a MAIN transformation
		int mainCount = 0;
		Template tpl = null;
		for (AcceleoSourceBuffer sb : buffers) {
			Template temp = AcceleoEngineActivator.getMainTemplate(sb);
			if (temp != null) {
				mainCount++;
				tpl = temp;
			}
		}
		
		templateNames.add(tpl.getName());
		module = (Module) tpl.eContainer();
		
		model = inputs[0];
		Vector<EObject> args = new Vector<EObject>();
		for (int i = 1; i < inputs.length; i++) {
			args.add(inputs[i]);
		}
		generationArguments = args;
		
		isInitialized = (mainCount == 1);
	}
	
	public boolean isInitialized() {
		return isInitialized;
	}

	public String getErrors() {
		return errors;
	}

}
